#ifndef AFCORE_DATABASE_DATABASE_DATABASE_MYSQL_CONNECTION_
#define AFCORE_DATABASE_DATABASE_DATABASE_MYSQL_CONNECTION_

#include <map>
#include <memory>
#include <mutex>
#include <string>
#include <vector>

#include "define.h"
#include "database_fwd.h"
#include "nocopyable.h"

namespace afcore {

template<typename T>
class CPcQueue;

/// @brief  数据库
namespace database {

class CDatabaseWorker;
class CPreparedStatementMysql;
class CSqlOperation;

/// @brief  mysql连接标志
enum EConnectionFlags {
  kConnectionFlags_Async = 0x1,   ///< 异步
  kConnectionFlags_Sync = 0x2,    ///< 同步
  kConnectionFlags_Both = kConnectionFlags_Async | kConnectionFlags_Sync ///< 两种方式都有
};

/// @brief  mysql连接信息
/// @note
///         "host;port_or_socket;user;password;database"
///
struct AFCORE_DATABASE_API SMysqlConnectionInfo {
  /// @brief  构造函数
  /// @param  info        连接信息字符串
  explicit SMysqlConnectionInfo(const std::string& info);

  std::string host;           ///< 数据库地址
  std::string port_or_socket; ///< 数据库端口号或套接字
  std::string user;           ///< 用户名
  std::string password;       ///< 密码
  std::string database;       ///< 数据库名称
};

class AFCORE_DATABASE_API CMysqlConnection
  : public CNocopyable {
  template <typename T> friend class CDatabaseWorkerPool;
  friend class CPingOperation;
public:
  /// @brief  构造函数 同步
  CMysqlConnection(SMysqlConnectionInfo& conn_info);
  /// @brief  构造函数 异步
  CMysqlConnection(SMysqlConnectionInfo& conn_info, CPcQueue<CSqlOperation*>* queue);
  /// @brief  析构函数
  virtual ~CMysqlConnection();

  /// @brief  打开连接
  virtual uint32_t Open();
  /// @brief  关闭连接
  void Close();

  /// @brief  准备状态
  /// @return true        预处理成功
  /// @return false       预处理成功 失败
  bool PrepareStatements();

  /// @brief  执行语句
  /// @param  sql         原生sql语句
  /// @return true        执行成功
  /// @return false       执行失败
  bool Execute(const char* sql);
  /// @brief  执行语句
  /// @param  stmt        预处理状态
  /// @return true        执行成功
  /// @return false       执行失败
  bool Execute(CPreparedStatementBase* stmt);

  /// @brief  查询语句
  /// @param  sql         原生sql语句
  /// @return 查询返回结果
  CResultSet* Query(const char* sql);
  /// @brief  查询语句
  /// @param  stmt        预处理状态
  /// @return 查询返回预处理结果
  CPreparedResultSet* Query(CPreparedStatementBase* stmt);

  /// @brief  开始事务
  void BeginTransaction();
  /// @brief  回滚事务
  void RollbackTransaction();
  /// @brief  提交事务
  void CommitTransaction();
  /// @brief  执行事务
  /// @param  transaction     事务
  /// @return 0               成功
  /// @return -1              事务队列空
  /// @return error_code      执行错误码 mysql_errno
  int ExecuteTransaction(std::shared_ptr<CTransactionBase> transaction);

  /// @brief  转义字符串
  /// @param  to          转义目的地
  /// @param  to          转义来源
  /// @param  length      转义长度
  /// @return 0           成功
  size_t EscapeString(char* to, const char* from, size_t length);

  /// @brief  ping
  void Ping();

  /// @brief  获取最后一次错误码
  /// @return 错误码
  uint32_t GetLastError();

protected:
  /// @brief  如果准备就绪就枷锁
  /// @return true        成功加锁
  /// @return false       加锁失败
  bool LockIfReady();
  /// @brief  解锁
  void Unlock();

  /// @brief  获取mysql服务器版本
  /// @return mysql服务器版本
  [[nodiscard]] uint32_t GetServerVersion() const;
  /// @brief  获取指定索引预处理语句
  /// @param  index           索引位置
  /// @return 指定索引预处理语句
  CPreparedStatementMysql* GetPreparedStatement(uint32_t index);
  /// @brief  预处理状态
  /// @param  index           索引位置
  /// @param  sql             sql语句
  /// @param  flags           mysql连接状态
  void PreparedStatement(uint32_t index, const std::string& sql, EConnectionFlags flags);

  /// @brief  执行预处理状态
  virtual void DoPreparedStatement() = 0;
private:
  /// @brief  原始sql查询
  /// @param  sql             原始sql语句
  /// @param  [out]   result          查询结果
  /// @param  [out]   fields          查询到的字段集合
  /// @param  [out]   row_count       查询到的数据行数
  /// @param  [out]   field_count     查询到的数据列数
  /// @return true                    查询成功
  /// @return false                   查询失败
  bool _Query(const char* sql, SMysqlResult** result, SMysqlField** fields, uint64_t* row_count, uint32_t* field_count);
  /// @brief  预处理语句查询
  /// @param  stmt            预处理语句
  /// @param  [out]   result          查询结果
  /// @param  [out]   row_count       查询到的数据行数
  /// @param  [out]   field_count     查询到的数据列数
  /// @return true                    查询成功
  /// @return false                   查询失败
  bool _Query(CPreparedStatementBase* stmt, SMysqlResult** result, uint64_t* row_count, uint32_t* field_count);

  /// @brief  处理mysql错误
  /// @param  error_no        错误码
  /// @param  attempts        尝试次数 默认5次
  /// @return true            处理成功
  /// @return false           处理失败
  bool HandleMysqlErrno(uint32_t error_no, uint8_t attempts = 5);
protected:
  using RPreparedStatementContainer = std::vector<std::unique_ptr<CPreparedStatementMysql>>;
  RPreparedStatementContainer stmts_; ///< 预处理状态容器
  bool reconnecting_ {false};         ///< 重连标志
  bool prepare_error_ {false};        ///< 预处理错误标志

private:
  CPcQueue<CSqlOperation*>* queue_ {nullptr};         ///< sql操作队列
  std::unique_ptr<CDatabaseWorker> worker_;           ///< 数据工作线程
  SMysqlHandle* mysql_ {nullptr};                     ///< mysql处理程序
  SMysqlConnectionInfo& conn_info_;                   ///< mysql连接信息
  EConnectionFlags conn_flags_;                       ///< mysql连接标志
  std::mutex mutex_;                                  ///< mysql互斥锁
};

} // !namespace database

} // !namespace afcore

#endif //! AFCORE_DATABASE_DATABASE_DATABASE_MYSQL_CONNECTION_